#include "mkvmuxfilter.hpp"
#include <uuids.h>
#include <dvdmedia.h>
#include "odbgstream.hpp"
using std::endl;
using std::boolalpha;

namespace MkvMux
{

InpinVideo::InpinVideo(Filter* p) :
    Inpin(p, L"video")
{
    AM_MEDIA_TYPE mt;
    
    mt.majortype = MEDIATYPE_Video;
    mt.subtype = MEDIASUBTYPE_MPEG2_VIDEO;  //TODO: more subtypes here
    
    mt.bFixedSizeSamples = FALSE;
    mt.bTemporalCompression = FALSE;
    mt.lSampleSize = 0;
    mt.formattype = GUID_NULL;
    mt.pUnk = 0;
    mt.cbFormat = 0;
    mt.pbFormat = 0;
    
    m_preferred.Add(mt);
}


InpinVideo::~InpinVideo()
{
}


HRESULT InpinVideo::QueryAccept(const AM_MEDIA_TYPE* pmt)
{
    if (pmt == 0)
        return E_INVALIDARG;
        
    const AM_MEDIA_TYPE& mt = *pmt;
    
    if (mt.majortype != MEDIATYPE_Video)
        return S_FALSE;
    
    if (mt.subtype != MEDIASUBTYPE_MPEG2_VIDEO)
        return S_FALSE;
        
    if (mt.formattype != FORMAT_MPEG2_VIDEO)
        return S_FALSE;

    //if (mt.cbFormat < sizeof(MPEG2VIDEOINFO))
    //    return S_FALSE;
        
    if (mt.cbFormat < (ULONG)FIELD_OFFSET(MPEG2VIDEOINFO, dwSequenceHeader[0]))
        return S_FALSE;

    if (mt.pbFormat == 0)
        return S_FALSE;
        
    const MPEG2VIDEOINFO& mpg = (MPEG2VIDEOINFO&)(*mt.pbFormat);

    if (mt.cbFormat < SIZE_MPEG2VIDEOINFO(&mpg))
        return S_FALSE;

    const VIDEOINFOHEADER2& vih = mpg.hdr;
    const BITMAPINFOHEADER& bmih = vih.bmiHeader;
    bmih;
    
    //TODO: anything else?
    //we have seqhdr
    
    return S_OK;  
}


HRESULT InpinVideo::GetAllocatorRequirements(ALLOCATOR_PROPERTIES* p)
{
    if (p == 0)
        return E_POINTER;
        
    ALLOCATOR_PROPERTIES& props = *p;
    
    //TODO: estimate this value based on value of framerate.
    props.cBuffers = 1;  //we copy payload immediately    
    props.cbBuffer = 0;
    props.cbAlign = 0;
    props.cbPrefix = 0;
    
    return S_OK;
}


HRESULT InpinVideo::OnReceive(IMediaSample* pSample)
{   
    //TODO: don't know what do about preroll samples
    //for now just ignore the issue
    
    //TODO: we'll probably need a secondary handler here,
    //that is codec-specific.  (That's why we can't
    //call this from our superclass.)
    
    //Each handler will know how to parse the media sample
    //(assuming that's required).
    
    //If we're here, the file object should already have been
    //initialized with video codec info.  But that doesn't 
    //mean the outpin is connected.
    
#if 0
    assert(m_pParser);
    
    if (pSample == 0)  //EOS
        m_pParser->SetEOS();  //?
    else
    {
        HRESULT hr = pSample->IsSyncPoint();
        const bool key = (hr == S_OK);

        if (key)
        {        
            __int64 st, sp;
            hr = pSample->GetTime(&st, &sp);
            
            odbgstream os;
            os << "OnReceive: key=" << boolalpha << key << " time=";
               
            if (hr == S_OK)
                os << "(st=" << st << ", sp=" << sp << ")";
            else if (SUCCEEDED(hr))
                os << "(st=" << st << ", sp=NONE)";
            else
                os << "NONE";
                
            os << endl;
        }
                
        BYTE* ptr;
        
        hr = pSample->GetPointer(&ptr);
        assert(SUCCEEDED(hr));
        assert(ptr);
        
        const long len = pSample->GetActualDataLength();
        assert(len >= 0);
        
        const int32_t result = m_pParser->WriteData(ptr, len);
        assert(result == 0);  //?
    }

    while (MPEGFrame* f = m_pParser->ReadFrame())
    {
        //HRESULT hr = m_pFilter->m_outpin.WriteVideo(f);
        //
        //if (hr != S_OK)
        //    return hr;
        
        const uint32_t size = f->size;
        const MediaTime mt = f->duration;
        const char ft = f->frameType;
        const MediaTime tc = f->timecode;
        
        if (ft == 'I')
        {
            odbgstream os;
            os << "I-frame: tc=" << tc << endl;
        }
        
        delete f;
        continue;
    }
#endif

    return m_pFilter->m_outpin.WriteVideo(pSample);
}


} //end namespace MkvMux
